package org.elastic.compreplatform.redis.util;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.session.Session;
import org.elastic.compreplatform.common.model.PageHelper;
import org.elastic.compreplatform.common.util.SerializationUtil;
import org.elastic.compreplatform.redis.core.factory.JedisConnectionFactory;
import org.elastic.compreplatform.redis.model.CacheModel;
import org.elastic.compreplatform.redis.model.RedisModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Tuple;

/**
 * ClassName: JedisUtil 
 * @Description: jedis工具类
 * @author JornTang
 * @date 2018年2月28日
 */
public class JedisUtil {
	private static Logger log = LoggerFactory.getLogger(JedisUtil.class);
	public static final String REDIS_SHIRO_SESSION = "elastic_compre_shiro_session:";
	public static final String REDIS_SHIRO_ALL = "*elastic_compre_shiro_session:*";
	public static final int SESSION_VAL_TIME_SPAN = 18000;
	public static final int DB_INDEX = 1;
	 /**
     * 缓存30分钟有效时间
     */
    public static int EXPIRE_30_MINUTE = 30*60;
    /**
     * 缓存一小时有效时间
     */
    public static int EXPIRE_1_HOUR = 60*60;
    /**
     * 缓存两个小时有效时间
     */
    public static int EXPIRE_2_HOUR = 60*60*2;
    /**
     * @Description: 根据key获取value
     * @param dbIndex
     * @param key
     * @return
     * @throws Exception   
     * @return byte[]  
     * @throws
     * @author JornTang
     * @date 2018年3月10日
     */
    public static byte[] getValueByKey(int dbIndex, byte[] key) throws Exception {
        Jedis jedis = null;
        byte[] result = null;
        try {
            jedis = JedisConnectionFactory.getJedis();
            jedis.select(dbIndex);
            result = jedis.get(key);
        } catch (Exception e) {
            throw e;
        } finally {
        	closeJedis(jedis);
        }
        return result;
    }

    public static void deleteByKey(int dbIndex, byte[] key) throws Exception {
        Jedis jedis = null;
        try {
            jedis = JedisConnectionFactory.getJedis();
            jedis.select(dbIndex);
            Long result = jedis.del(key);
            log.info("删除Session结果：{}" , result);
        } catch (Exception e) {
            throw e;
        } finally {
        	closeJedis(jedis);
        }
    }

    public static void saveValueByKey(int dbIndex, byte[] key, byte[] value, int expireTime)
            throws Exception {
        Jedis jedis = null;
        try {
            jedis = JedisConnectionFactory.getJedis();
            jedis.select(dbIndex);
            jedis.set(key, value);
            if (expireTime > 0)
                jedis.expire(key, expireTime);
        } catch (Exception e) {
            throw e;
        } finally {
            closeJedis(jedis);
        }
    }
	/**
	 * 获取所有Session
	 * @param dbIndex
	 * @param redisShiroSession
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public static Collection<Session> AllSession(int dbIndex, String redisShiroSession) throws Exception {
		Jedis jedis = null;
        Set<Session> sessions = new HashSet<Session>();
		try {
            jedis = JedisConnectionFactory.getJedis();
            jedis.select(dbIndex);
            
            Set<byte[]> byteKeys = jedis.keys(REDIS_SHIRO_ALL.getBytes());  
            if (byteKeys != null && byteKeys.size() > 0) {  
                for (byte[] bs : byteKeys) {  
                	Session obj = SerializationUtil.deserialize(jedis.get(bs),  
                    		 Session.class);  
                     if(obj instanceof Session){
                    	 sessions.add(obj);  
                     }
                }  
            }  
        } catch (Exception e) {
            throw e;
        } finally {
            closeJedis(jedis);
        }
        return sessions;
	}
	/**
	 * @Description: 根据db,key获取所有缓存信息
	 * @param redisModel
	 * @param dbIndex
	 * @param cacheKey
	 * @param page
	 * @return   
	 * @return String  
	 * @throws
	 * @author JornTang
	 * @date 2018年2月28日
	 */
	public static void getPageForJedisCache(RedisModel model, Integer dbIndex, String cacheKey, PageHelper page) {
		if(model == null) {
			return;
		}
		JedisPool jedisPool = JedisConnectionFactory.buildJedisPool(model.getDbUrl(), model.getDbPort());
		Jedis jedis = jedisPool.getResource();
		//密码验证
		if(StringUtils.isNotEmpty(model.getPassword())) {
			jedis.auth(model.getPassword());
		}
		int limitFrom = page.getOffset();
		int pageSize = page.getLimit();
		List<Map<String, Object>> list = new ArrayList();
		try {
			jedis.select(dbIndex);
			Long dbSize = jedis.dbSize();
			Set nodekeys = new HashSet();

			if (cacheKey.equals("nokey")) {
				if (dbSize.longValue() > 1000L) {
					for (int z = 0; z < pageSize; z++) {
						nodekeys.add(jedis.randomKey());
					}
				} else {
					nodekeys = jedis.keys("*");
				}
			} else {
				nodekeys = jedis.keys("*" + cacheKey + "*");
			}
			Iterator it = nodekeys.iterator();

			int i = 1;
			String value = "";
			while (it.hasNext()) {
				if ((i >= limitFrom) && (i <= limitFrom + pageSize)) {

					Map<String, Object> map = new HashMap();
					String key = (String) it.next();
					String type = jedis.type(key);
					map.put("key", key);
					map.put("type", type);

					if (type.equals("string")) {
						value = jedis.get(key);
						if (value.length() > 80) {
							map.put("value", value.substring(0, 79) + "......");
						} else {
							map.put("value", value);
						}
					}

					if (type.equals("list")) {
						Long lon = jedis.llen(key);
						if (lon.longValue() > 20L) {
							lon = Long.valueOf(20L);
						}
						map.put("value", jedis.lrange(key, 0L, lon.longValue()));
					}
					if (type.equals("set")) {
						map.put("value", jedis.smembers(key).toString());
					}

					if (type.equals("zset")) {
						Long lon = jedis.zcard(key);
						if (lon.longValue() > 20L) {
							lon = Long.valueOf(20L);
						}

						Set<Tuple> set = jedis.zrangeWithScores(key, 0L, lon.longValue());
						Iterator<Tuple> itt = set.iterator();
						String ss = "";
						while (itt.hasNext()) {
							Tuple str = (Tuple) itt.next();
							ss = ss + "[" + str.getScore() + "," + str.getElement() + "],";
						}
						ss = ss.substring(0, ss.length() - 1);
						map.put("value", "[" + ss + "]");
					}

					if (type.equals("hash")) {
						map.put("value", jedis.hgetAll(key).toString());
					}
					list.add(map);
				} else {
					it.next();
				}
				i++;
			}
			if (cacheKey.equals("nokey")) {
				page.setCount(Integer.valueOf(Integer.parseInt(dbSize.toString())));
			} else {
				page.setCount(Integer.valueOf(i));
			}

		} catch (Exception e) {

		} finally {
			jedis.close();
		}
		page.setData(list);
	    
	}
	/**
	 * @Description: 获取redis统计信息
	 * @param model
	 * @return   
	 * @return String  
	 * @throws
	 * @author JornTang
	 * @date 2018年2月28日
	 */
	public static String getJedisInfo(RedisModel model) {
		if(model == null) {
			return null;
		}
		JedisPool jedisPool = JedisConnectionFactory.buildJedisPool(model.getDbUrl(), model.getDbPort());
		Jedis jedis = jedisPool.getResource();
		//密码验证
		if(StringUtils.isNotEmpty(model.getPassword())) {
			jedis.auth(model.getPassword());
		}
		return jedis.info();
	}
	/**
	 * @Description: 获取所有redis库
	 * @param redisModel
	 * @return   
	 * @return int  
	 * @throws
	 * @author JornTang
	 * @date 2018年2月28日
	 */
	public static int getAmountForRedis(RedisModel model) {
		if(model == null) {
			return 0;
		}
		JedisPool jedisPool = JedisConnectionFactory.buildJedisPool(model.getDbUrl(), model.getDbPort());
		Jedis jedis = jedisPool.getResource();
		//密码验证
		if(StringUtils.isNotEmpty(model.getPassword())) {
			jedis.auth(model.getPassword());
		}
		List<String> list = jedis.configGet("databases");
		int amount = 1;
		if (list.size() > 0) {
			amount = Integer.parseInt((String)list.get(1));
	    } else {
	    	amount = 15;
	    }
		if(jedis != null) {
			jedis.close();
		}
		return amount;
	}
	/**
	 * @Description: 添加缓存
	 * @param redisModel
	 * @param cache
	 * @return   
	 * @return boolean  
	 * @throws
	 * @author JornTang
	 * @date 2018年2月28日
	 */
	public static boolean saveForRedis(RedisModel model, CacheModel cache) {
		if(model == null) {
			return false;
		}
		JedisPool jedisPool = JedisConnectionFactory.buildJedisPool(model.getDbUrl(), model.getDbPort());
		Jedis jedis = jedisPool.getResource();
		//密码验证
		if(StringUtils.isNotEmpty(model.getPassword())) {
			jedis.auth(model.getPassword());
		}
		try {
			Integer dbIndex = cache.getDbIndex();

			jedis.select(dbIndex);

			String key = cache.getKey();
			String value = cache.getKeyValue();
			value = StringEscapeUtils.unescapeHtml4(value);
			String type = cache.getKeyType();
			int o1 = Integer.parseInt(cache.getExpire());
			if (type.equals("string")) {
				value = jedis.set(key, value);
			}
			if (type.equals("list")) {

				String[] valuek = cache.getValuek();
				jedis.del(new String[] { key });

				for (int i = valuek.length; i > 0; i--) {
					if (i == valuek.length) {
						jedis.lpush(key, new String[] { valuek[(i - 1)] });
					} else {
						jedis.lpushx(key, valuek[(i - 1)]);
					}
				}
			}

			if (type.equals("set")) {

				String[] valuek = cache.getValuek();
				jedis.del(new String[] { key });

				String members = "";
				for (int i = 0; i < valuek.length; i++) {
					if (i == 0) {
						members = members + valuek[i];
					} else {
						members = members + "," + valuek[i];
					}
				}
				jedis.sadd(key, new String[] { members });
			}

			if (type.equals("zset")) {
				String[] zsetKey = cache.getValuek();
				String[] zsetValue = cache.getValuev();
				jedis.del(new String[] { key });

				Map<String, Double> scoreMembers = new HashMap();
				for (int i = zsetKey.length; i > 0; i--) {
					String _zsetKey = zsetKey[(i - 1)].trim();
					Double _zsetValue = Double.valueOf(Double.parseDouble(zsetValue[(i - 1)].trim()));
					if (_zsetValue == null) {
						_zsetValue = 0D;
					}
					scoreMembers.put(_zsetKey, _zsetValue);
				}
				jedis.zadd(key, scoreMembers);
			}

			if (type.equals("hash")) {

				String[] valuek = cache.getValuek();
				String[] valueV = cache.getValuev();
				jedis.del(new String[] { key });

				Map<String, String> hashmm = new HashMap<String, String>();
				for (int i = valuek.length; i > 0; i--) {
					String valuekkk = valuek[(i - 1)].trim();
					String valuevvv = valueV[(i - 1)].trim();
					if (valuevvv == null) {
						valuevvv = "";
					}
					hashmm.put(valuekkk, valuevvv);
				}
				jedis.hmset(key, hashmm);
			}

			if (o1 != -1) {
				jedis.expire(key, o1);
			}
			return true;
		} catch (Exception e) {
			log.error("添加缓存异常", e);
			return false;
		} finally {
			if(jedis != null) {
				jedis.close();
			}
		}
	}
	/**
	 * @Description: 删除缓存
	 * @param redisModel
	 * @param cache
	 * @return   
	 * @return boolean  
	 * @throws
	 * @author JornTang
	 * @date 2018年2月28日
	 */
	public static boolean deleteKeys(RedisModel model, CacheModel cache) {
		if(model == null) {
			return false;
		}
		JedisPool jedisPool = JedisConnectionFactory.buildJedisPool(model.getDbUrl(), model.getDbPort());
		Jedis jedis = jedisPool.getResource();
		//密码验证
		if(StringUtils.isNotEmpty(model.getPassword())) {
			jedis.auth(model.getPassword());
		}
		try {
			jedis.select(cache.getDbIndex());
			String[] keys = StringUtils.isNotEmpty(cache.getKeys()) ? cache.getKeys().split(",") : null;
			if (keys != null) {
				for (int i = 0; i < keys.length; i++) {
					jedis.del(new String[] { keys[i] });
				}
			}
			return true;
		} catch (Exception e) {
			log.error("删除缓存异常", e);
			return false;
		} finally {
			if(jedis != null) {
				jedis.close();
			}
		}
	}
	/**
	 * @Description: 获取redis缓存
	 * @param redisModel
	 * @param cache
	 * @return   
	 * @return CacheModel  
	 * @throws Exception 
	 * @throws
	 * @author JornTang
	 * @date 2018年3月1日
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static CacheModel selectForRedis(RedisModel redisModel, CacheModel cache) throws Exception {
	    Map<String, Object> map = selectForRedis(redisModel, cache.getKey(), cache.getDbIndex());
		String type = (String) map.get("type");
		cache.setKeyType((String) map.get("type"));
		cache.setExpire(map.get("expire")+"");

		if (type.equals("string")) {
			cache.setKeyValue((String) map.get("value"));
		}

		if (type.equals("list")) {
			cache.setList((List) map.get("value"));
		}

		if (type.equals("set")) {
			String temp = (String) map.get("value");
			temp = temp.substring(1, temp.length() - 1);
			String[] arr = temp.split(",");
			cache.setList(Arrays.asList(arr));
		}
		if (type.equals("zset")) {
			Object temp = map.get("value");
			Set<Tuple> set = (Set<Tuple>) temp;
			Iterator<Tuple> itt = set.iterator();
			List<Map<String, Object>> listMap = new ArrayList<Map<String, Object>>();

			while (itt.hasNext()) {
				Tuple str = (Tuple) itt.next();
				Map<String, Object> mm = new HashMap<String, Object>();
				mm.put("valuek", Double.valueOf(str.getScore()));
				mm.put("valuev", str.getElement());
				listMap.add(mm);
			}

			cache.setListMap(listMap);
		}

		if (type.equals("hash")) {
			Map<String, String> hashMap = (Map<String, String>) map.get("value");
			List<Map<String, Object>> listMap = new ArrayList();

			for (Map.Entry<String, String> entry : hashMap.entrySet()) {
				Map<String, Object> keyMap = new HashMap();
				keyMap.put("valuek", entry.getKey());
				keyMap.put("valuev", entry.getValue());
				listMap.add(keyMap);
			}
			cache.setListMap(listMap);
		}
		return cache;
	}
	/**
	 * @Description: 获取redis缓存
	 * @param redisModel
	 * @param cache
	 * @return   
	 * @return CacheModel  
	 * @throws Exception 
	 * @throws
	 * @author JornTang
	 * @date 2018年3月1日
	 */
	public static Map<String, Object> selectForRedis(RedisModel model, String key, Integer dbIndex) throws Exception {
		Jedis jedis = doAuthorJedis(model);
		
		Map<String, Object> map = new HashMap<String, Object>();
		jedis.select(dbIndex);
		String type = jedis.type(key);
		Long expire = jedis.ttl(key);
		map.put("key", key);
		map.put("type", type);
		map.put("expire", expire);
		if (type.equals("string")) {
			map.put("value", jedis.get(key));
		}
		if (type.equals("list")) {
			Long lon = jedis.llen(key);
			map.put("value", jedis.lrange(key, 0L, lon.longValue()));
		}
		if (type.equals("set")) {
			map.put("value", jedis.smembers(key).toString());
		}
		if (type.equals("zset")) {

			Set<Tuple> set = jedis.zrangeWithScores(key, 0L, -1L);
			map.put("value", set);
		}
		if (type.equals("hash")) {
			map.put("value", jedis.hgetAll(key));
		}
		if(jedis != null) {
			jedis.close();
		}
		return map;
	}
	/**
	 * @Description: 获取jedis实例并验证密码
	 * @return   
	 * @return Jedis  
	 * @throws
	 * @author JornTang
	 * @date 2018年3月1日
	 */
	public static Jedis doAuthorJedis(RedisModel model) throws Exception{
		if(model == null) {
			return null;
		}
		JedisPool jedisPool = JedisConnectionFactory.buildJedisPool(model.getDbUrl(), model.getDbPort());
		Jedis jedis = jedisPool.getResource();
		//密码验证
		if(StringUtils.isNotEmpty(model.getPassword())) {
			jedis.auth(model.getPassword());
		}
		return jedis;
	}
	/**
	 * @Description: 清理所有缓存数据
	 * @param redisModel
	 * @param cache
	 * @return   
	 * @return boolean  
	 * @throws
	 * @author JornTang
	 * @date 2018年3月1日
	 */
	public static void flushAll(RedisModel model) throws Exception{
		Jedis jedis = doAuthorJedis(model);
		jedis.flushAll();
		if(jedis != null) {
			jedis.close();
		}
	}
	/**
	 * @Description: 清理指定库缓存数据
	 * @param redisModel
	 * @param cache   
	 * @return void  
	 * @throws Exception 
	 * @throws
	 * @author JornTang
	 * @date 2018年3月1日
	 */
	public static void flushDb(RedisModel model, CacheModel cache) throws Exception {
		Jedis jedis = doAuthorJedis(model);
		jedis.select(cache.getDbIndex());
		jedis.flushDB();
		if(jedis != null) {
			jedis.close();
		}
	}
	/**
	 * @Description: 重置统计信息
	 * @param redisModel   
	 * @return void  
	 * @throws
	 * @author JornTang
	 * @date 2018年3月2日
	 */
	public static void clearInfo(RedisModel model) throws Exception{
		Jedis jedis = doAuthorJedis(model);
		jedis.configResetStat();
		//jedis.resetState();
		if(jedis != null) {
			jedis.close();
		}
	}
	/**
	 * @Description: redis备份
	 * @param redisModel   
	 * @return void  
	 * @throws Exception 
	 * @throws
	 * @author JornTang
	 * @date 2018年3月4日
	 */
	public static void backupDatabase(RedisModel model) throws Exception {
		Jedis jedis = doAuthorJedis(model);
		//异步保存当前数据库
		jedis.bgsave();
		//获取备份路径
		List<String> list = jedis.configGet("dir");
	      for (int i = 0; i < list.size(); i++) {
	        //value = (String)list.get(i);
	      }
	}
	public static void closeJedis(Jedis jedis) {
		if(jedis!= null) {
			jedis.close();
		}
	}
}
